package org.example.Polls;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.basic.DateConverter;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.DomReader;

public class SOAPUnmarshaller {
	
	private Document document;
	
	private NamespaceContext nsContext = new NamespaceContext(){
	    public String getNamespaceURI(String prefix) {
	        if (prefix == null) throw new NullPointerException("Null prefix");
	        else if ("soap".equals(prefix)) return "http://schemas.xmlsoap.org/soap/envelope/";
	        else if ("xml".equals(prefix)) return XMLConstants.XML_NS_URI;
	        return XMLConstants.NULL_NS_URI;
	    }
	    // This method isn't necessary for XPath processing.
	    public String getPrefix(String uri) { throw new UnsupportedOperationException(); }
	    // This method isn't necessary for XPath processing either.
	    public Iterator getPrefixes(String uri) { throw new UnsupportedOperationException(); }
	};

	public SOAPUnmarshaller(String doc) throws ParserConfigurationException, 
		                                       IOException, 
		                                       SAXException, 
		                                       XPathExpressionException {
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setNamespaceAware(true);
		DocumentBuilder builder = factory.newDocumentBuilder();
		ByteArrayInputStream is = new ByteArrayInputStream(doc.getBytes("UTF-8"));
		this.document = builder.parse(is);
		
		// check here for SOAP faults.
		XPathFactory xpFactory = XPathFactory.newInstance();
		XPath xpath = xpFactory.newXPath();
		xpath.setNamespaceContext(nsContext);
		Node node = (Node) xpath.evaluate("//soap:Fault", document, XPathConstants.NODE);
		if (node != null) {
			String faultstring = (String)xpath.evaluate("//soap:Fault/faultstring", document, XPathConstants.STRING);
			throw new SOAPFault (faultstring);
		}
	}
	
	public List unmarshal (String xpathExpr) throws InstantiationException, 
													IllegalAccessException, 
													XPathExpressionException {
		XStream xstream = XStreamManager.getInstance().getXStream();
		List objList = new ArrayList();
		// XXX: clazz has to know to unmarshal nested objects.
		XPathFactory xpFactory = XPathFactory.newInstance();
		XPath xpath = xpFactory.newXPath();
		xpath.setNamespaceContext(nsContext);
		NodeList nodeList = (NodeList) xpath.evaluate(xpathExpr, document, XPathConstants.NODESET);
		if (nodeList != null) {
    		for (int i=0; i < nodeList.getLength(); i++) {
    			Node node = nodeList.item(i);
        		objList.add(xstream.unmarshal(new DomReader((Element)node)));
    		}
		}
		return objList;
	}

}
